use std::sync::LazyLock;
use anyhow::Context;
use config::Config;
use serde::Deserialize;
use crate::config::database::DatabaseConfig;
use crate::config::redis::RedisConfig;
use crate::config::server::ServerConfig;
use crate::config::token::TokenConfig;

pub use token::{TokenType, TokenStyle};

mod server;
mod database;
mod redis;
mod token;

static CONFIG: LazyLock<AppConfig> = LazyLock::new(|| AppConfig::load().expect("Failed initialize AppConfig"));

/// 应用程序集成配置
///
/// # 属性
/// - `server` - 服务基础配置
#[derive(Debug ,Deserialize)]
pub struct AppConfig {
    server: ServerConfig,
    database: DatabaseConfig,
    redis: RedisConfig,
    token: TokenConfig
}

impl AppConfig {
    /// 加载应用程序配置
    pub fn load() -> anyhow::Result<Self> {
        Config::builder()
            .add_source(
                config::File::with_name("application")
                    .format(config::FileFormat::Yaml)
                    .required(true)
            )
            .add_source(
                config::Environment::with_prefix("APP")
                    .try_parsing(true)
                    .separator("_")
                    .list_separator(",")
            ).build()?.try_deserialize().with_context(|| "failed to parse application config")
    }

    pub fn server(&self) -> anyhow::Result<&ServerConfig> {
        Ok(&self.server)
    }

    pub fn database(&self) -> anyhow::Result<&DatabaseConfig> {
        Ok(&self.database)
    }

    pub fn redis(&self) -> anyhow::Result<&RedisConfig> { Ok(&self.redis) }

    pub fn token(&self) -> anyhow::Result<&TokenConfig> { Ok(&self.token) }
}

/// 获取AppConfig
pub fn get() -> &'static AppConfig {
    &CONFIG
}